package com.bocek.chakmapoint.model;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.geom.Point2D;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * A rectangle slide item.
 * 
 * @author Emin Bugra Saral
 * @version 1.3
 */

public class CRectangle extends Rectangle implements SlideItem {

	private static final long serialVersionUID = 6939019440051215662L;

	// defaults
	private Selection selection = Selection.NONE;
	private boolean selected = false;
	private boolean filled = false;
	private String name = "Rectangle";
	private Color color = Color.black;
	private int thickness = 1;
	private Point2D startPoint;

	// testing change in defaults
	public boolean repOK() {
		boolean ok = true;

		ok &= (name.equals("Rectangle"));
		ok &= (thickness > 0);
		ok &= (color != null);
		ok &= (selection != null);

		if (!ok)
			System.out.println("error found");

		return ok;
	}

	public CRectangle(Point p) {
		super();
		this.startPoint = p;
	}

	public void addPoint(Point p) {
		int firstX = (int) startPoint.getX();
		int firstY = (int) startPoint.getY();

		int secondX = (int) p.getX();
		int secondY = (int) p.getY();

		int width = Math.abs(firstX - secondX);
		int height = Math.abs(firstY - secondY);

		if ((firstX > secondX) && (firstY <= secondY)) {
			this.setRect(secondX, firstY, width, height);
		} else if ((firstX <= secondX) && (firstY > secondY)) {
			this.setRect(firstX, secondY, width, height);
		} else if ((firstX > secondX) && (firstY > secondY)) {
			this.setRect(secondX, secondY, width, height);
		} else {
			this.setRect(firstX, firstY, width, height);
		}
	}

	/**
	 * Default constructor.
	 * 
	 * @requires Nothing.
	 * @modifies Nothing.
	 * @effects Constructs a new Rectangle whose top-left corner is at (0, 0) in
	 *          the coordinate space, and whose width and height are both zero.
	 */
	public CRectangle() {
		super();
	}

	/**
	 * Custom constructor with the initial point, width and height.
	 * 
	 * @requires initial point p which is in frame, width and height greater
	 *           than zero.
	 * @modifies Nothing.
	 * @effects Constructs a new Rectangle whose top-left corner is specified by
	 *          the Point argument, and whose width and height are specified by
	 *          int arguments.
	 */
	public CRectangle(Point p, int width, int height) {
		super(p, new Dimension(width, height));
	}

	/**
	 * Custom constructor with the start and end points.
	 * 
	 * @requires Two points from crosswise corners of the rectanglef
	 * @modifies Nothing.
	 * @effects Constructs a new Rectangle whose top-left corner is specified by
	 *          the startPoint argument, and whose width and height are
	 *          specified by the difference of endPoint and startPoint
	 *          arguments.
	 */
	public CRectangle(Point startPoint, Point endPoint) {
		super((int) startPoint.getX(), (int) startPoint.getY(), (int) (endPoint
				.getX() - startPoint.getX()),
				(int) (endPoint.getY() - startPoint.getY()));
	}

	/**
	 * Set the current selection.
	 * 
	 * @requires A Selection object, s.
	 * @modifies selection attribute of the CRectangle object.
	 * @effects Nothing.
	 */
	public void setSelection(Selection s) {
		selection = s;
	}

	/**
	 * Get the current selection.
	 * 
	 * @requires Nothing.
	 * @modifies Nothing.
	 * @effects Returns the current selection of the CRectangle object.
	 */
	public Selection getSelection() {
		return this.selection;
	}

	/**
	 * Set the thickness size.
	 * 
	 * @requires An integer greater than zero, t.
	 * @modifies thickness attribute of the CRectangle object.
	 * @effects Nothing.
	 */
	public void setThickness(int t) {
		this.thickness = t;
	}

	/**
	 * Get the current selection.
	 * 
	 * @requires Nothing.
	 * @modifies Nothing.
	 * @effects Returns the current thickness size of CRectangle object.
	 */
	public int getThickness() {
		return this.thickness;
	}

	public void setFilled(boolean b) {
		this.filled = b;
	}

	public boolean isFilled() {
		return this.filled;
	}

	@Override
	public String getName() {
		return name;
	}

	public Rectangle drawSelection() {
		Rectangle r = new Rectangle(this);
		r.setBounds(r.x - 2, r.y - 2, r.width + 4, r.height + 4);
		return r;
	}

	@Override
	public void draw(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		Color previousColor = g2d.getColor();
		Stroke previousStroke = g2d.getStroke();

		g2d.setColor(color);
		g2d.setStroke(new BasicStroke(thickness));

		if (isFilled())
			g2d.fill((Rectangle) this);
		else
			g2d.draw((Rectangle) this);

		if (isSelected()) {
			// dashed line
			g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND,
					BasicStroke.JOIN_ROUND, 0.0f, new float[] { 4.0f, 4.0f },
					0.9f));
			g2d.setColor(Color.BLUE);
			g2d.draw(this.drawSelection());
		}

		g2d.setStroke(previousStroke);
		g2d.setColor(previousColor);
	}

	@Override
	public boolean isPointInside(Point p) {
		return contains(p);
	}

	@Override
	public boolean select(Point p) {
		// check by area
		if (isPointInside(p)) {
			setSelection(Selection.ALL);
			selected = true;
		} else {
			setSelection(Selection.NONE);
			selected = false;
			return false;
		}

		return true;
	}

	@Override
	public boolean deselect() {
		if (getSelection() != Selection.NONE)
			setSelection(Selection.NONE);
		this.selected = false;
		return true;
	}

	@Override
	public boolean isSelected() {
		return this.selected;
	}

	@Override
	public void move(Point delta) {
		// create a new point at new distance
		Point p = new Point(delta);
		p.setLocation(p.x + this.getX(), p.y + this.getY());
		setLocation(p);
	}

	@Override
	public boolean isOutsideFrame(Dimension frameDimension) {
		// check for x-coordinate
		if (this.getWidth() + this.getX() > frameDimension.width
				|| this.getX() < 0) {
			return true;
		}
		// check for y-coordinate
		else if (this.getHeight() + this.getY() > frameDimension.height
				|| this.getY() < 0) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public void setColor(Color c) {
		this.color = c;

	}

	@Override
	public Color getColor() {
		return this.color;
	}

	@Override
	public void setSelected(boolean b) {
		this.selected = b;
	}
	
	@Override
	public void fill() {
		if (isFilled()) {
			setFilled(false);
		}
		else {
			setFilled(true);
		}
	}
	
	@Override
	public Element saveToXML(Document doc, int depth) {
		/*
		 <rectangle thickness="" color="" width="4" height="5" isFilled="true" depth="3" topX="2" leftY="3"/>
		*/
		
		// DEFAULT
		
		Element e = doc.createElement("rectangle");
		e.setAttribute("thickness", Integer.toString(this.thickness));
		e.setAttribute("color", Integer.toString(this.color.getRGB()));
		e.setAttribute("width", Integer.toString((int) this.getWidth()));
		e.setAttribute("height", Integer.toString((int) this.getHeight()));
		e.setAttribute("isFilled", Boolean.toString(this.filled));
		e.setAttribute("depth", Integer.toString(depth));
		e.setAttribute("topX", Integer.toString((int) this.getX()));
		e.setAttribute("leftY", Integer.toString((int) this.getY()));
		
		return e;
	}

}
